package com.woniu.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.account.dao.TAdminInfoMapper;
import com.woniu.account.dao.TAdminRoleMapper;
import com.woniu.account.dao.TCoachMapper;
import com.woniu.account.dao.TRoleMapper;
import com.woniu.account.dto.AdminLoginDto;
import com.woniu.account.dto.LoginLogDto;
import com.woniu.account.dto.PageAdminDTO;
import com.woniu.account.dto.UserPointDto;
import com.woniu.account.form.*;
import com.woniu.account.model.*;
import com.woniu.account.service.TAdminInfoService;
import com.woniu.account.service.TAdminRoleService;
import com.woniu.account.service.TLoginLogService;
import com.woniu.account.service.TRoleService;
import com.woniu.core.exception.account.AccountException;
import com.woniu.core.exception.account.AccountExceptionCode;
import com.woniu.core.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;

import static com.woniu.core.exception.account.AccountExceptionCode.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 吴彦祖
 * @since 2024年04月02日
 */
@Service
public class TAdminInfoServiceImpl extends ServiceImpl<TAdminInfoMapper, TAdminInfo> implements TAdminInfoService {

    @Autowired
    private TRoleMapper tRoleMapper;
    @Autowired
    private TCoachMapper tCoachMapper;
    @Autowired
    private TAdminInfoMapper tAdminInfoMapper;
    @Autowired
    private TAdminRoleService tAdminRoleService;
    @Autowired
    private TAdminRoleMapper tAdminRoleMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private TLoginLogService tLoginLogService;
    @Resource
    private AliyunOSSUtil aliyunOSSUtil;
    @Override
    public AdminLoginDto adminLogin(LoginForm form) throws Exception {
        //判断账号密码是否正确
        TAdminInfo admin = getOne(new QueryWrapper<TAdminInfo>()
                .eq("admin_name", form.getAdminName()));
        if (admin==null) throw new AccountException("账号不存在",400001);

        String salt = form.getAdminName();
        int index = 0;
        int count = 2;
        MD5 md5 = new MD5(salt.getBytes(StandardCharsets.UTF_8),index,count);
        if(!md5.digestHex(form.getAdminPass()).equals(admin.getAdminPass())){
            throw new AccountException("密码错误",400001);
        }
        if(admin.getAdminState()!= 1){
            throw new AccountException("账号状态异常",400001);
        }
        //获得返回对象
        AdminLoginDto adminLoginDTO = new AdminLoginDto();
        adminLoginDTO.setAdminId(admin.getAdminId());
        adminLoginDTO.setAdminName(admin.getAdminName());
        TAdminRole adminRole = tAdminRoleService.getOne(new QueryWrapper<TAdminRole>().eq("admin_id", admin.getAdminId()));
        TRole role = tRoleMapper.selectById(adminRole.getRoleId());
        adminLoginDTO.setRole(role.getRoleName());
        //创建token
        Map<String,Object> maps = new HashMap<>();
        maps.put("adminId", adminLoginDTO.getAdminId());
        maps.put("adminRole", adminLoginDTO.getRole());
        //创建短token
        String accessToken = JwtUtil.createToken(maps, 30,1);
        //创建长token,续期
        String refreshToken = JwtUtil.createToken(maps, 60 * 24,1);
        //token为键，长token为值，存入redis
        redisUtil.set(accessToken,refreshToken,24L*60L*60L);
        //将token放入响应头
        WebUtil.getResponse().setHeader("access",accessToken);
        WebUtil.getResponse().addHeader("Access-Control-Expose-Headers","access");

        //添加登录日志
        TLoginLog log = new TLoginLog();
        log.setLoginRole(4);
        log.setAccountId(admin.getAdminId());
        log.setAccountName(admin.getAdminName());
        String ipAddr = JwtUtil.getIpAddr(WebUtil.getRequest());
        log.setAddressIp(ipAddr);
        log.setLogInfo("登录成功");
        log.setLogDate(LocalDateTime.now());
        boolean b = tLoginLogService.save(log);
        if (!b) throw new AccountException(LOGIN_ERROR);
        return adminLoginDTO;
    }

    @Override
    public Boolean addAdminAccount(AddAdminForm form) throws Exception {
        //新增的adminInfo表
        QueryWrapper<TAdminInfo> wrapper = new QueryWrapper<TAdminInfo>();
        wrapper.eq("admin_name",form.getAdminName());
        wrapper.or();
        wrapper.eq("admin_phone",form.getAdminPhone());
        List<TAdminInfo> list = tAdminInfoMapper.selectList(wrapper);
        if(list.size()>0){
            throw new AccountException("用户名或手机号已存在",400001);
        }
        TAdminInfo account = BeanUtil.toBean(form,TAdminInfo.class);
        account.setAdminState(1);
        String salt = form.getAdminName();
        int index = 0;
        int count = 2;
        MD5 md5 = new MD5(salt.getBytes(StandardCharsets.UTF_8),index,count);
        account.setAdminPass(md5.digestHex(account.getAdminPass()));
        tAdminInfoMapper.insert(account);


        //新增admin_role表 新增的都是普通管理员：角色id=2
        TAdminRole accountRole = new TAdminRole();
        accountRole.setAdminId(account.getAdminId());
        accountRole.setRoleId(2);
        tAdminRoleMapper.insert(accountRole);

        return true;
    }

    @Override
    public Boolean sendLoginCode(String phone) throws Exception {
        //发送登录验证码时，要验证手机号是否注册过，注册过才发验证码
        QueryWrapper<TAdminInfo> wrapper = new QueryWrapper<TAdminInfo>();
        wrapper.eq("admin_phone", phone);
        TAdminInfo userInfo = tAdminInfoMapper.selectOne(wrapper);
        if (userInfo == null) {
            throw new AccountException("手机号还未注册",400001);
        }
        String code = "123456";
        //redis保存一份验证码，为了登录时的验证
        redisUtil.set(RedisKeyUtil.sendLoginCodeKey(phone), code, 300);
        //一分钟内不能同时发送的标识
        redisUtil.set(RedisKeyUtil.sendLoginCodeInMinute(phone), "", 60);
        //判断24小时内的次数限定
        if (redisUtil.exist(RedisKeyUtil.sendCodeNumberOn24hour(phone))) {
            //存在就调用util自增1的方法，为了判断是否达到5条
            redisUtil.incr(RedisKeyUtil.sendCodeNumberOn24hour(phone));
        } else {
            //如果没有发送过的话，就要加1
            redisUtil.set(RedisKeyUtil.sendCodeNumberOn24hour(phone), "1", 24 * 60 * 60);
        }
        return true;
    }

    @Override
    public AdminLoginDto adminCodeLogin(AdminInfoCodeLoginForm form) throws Exception {
        //取出之前的登录验证码key
        //前端传过来的是用Interger的类型，这里就要强转
        int code = Integer.parseInt(redisUtil.get(RedisKeyUtil.sendLoginCodeKey(form.getAdminPhone())));
        if (form.getCode() != code) {
            if (!redisUtil.exist(RedisKeyUtil.errorTotal(form.getAdminPhone()))) {
                redisUtil.set(RedisKeyUtil.errorTotal(form.getAdminPhone()), "1", 5 * 60);
            } else {
                redisUtil.incr(RedisKeyUtil.errorTotal(form.getAdminPhone()));
            }
            throw new AccountException("验证码错误",400001);
        }
        //登录就不用判断了，因为收到了验证码，证明无异常,直接查
        QueryWrapper<TAdminInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("admin_phone", form.getAdminPhone());
        TAdminInfo adminInfo = tAdminInfoMapper.selectOne(wrapper);
        AdminLoginDto adminLoginDTO = BeanUtil.toBean(adminInfo, AdminLoginDto.class);

        adminLoginDTO.setAdminId(adminInfo.getAdminId());
        adminLoginDTO.setAdminName(adminInfo.getAdminName());
        TAdminRole adminRole = tAdminRoleService.getOne(new QueryWrapper<TAdminRole>().eq("admin_id", adminInfo.getAdminId()));
        TRole role = tRoleMapper.selectById(adminRole.getRoleId());
        adminLoginDTO.setRole(role.getRoleName());
        //创建token
        Map<String,Object> maps = new HashMap<>();
        maps.put("adminId", adminLoginDTO.getAdminId());
        maps.put("adminRole", adminLoginDTO.getRole());
        //创建短token
        String accessToken = JwtUtil.createToken(maps, 30,1);
        //创建长token,续期
        String refreshToken = JwtUtil.createToken(maps, 60 * 24,1);
        //token为键，长token为值，存入redis
        redisUtil.set(accessToken,refreshToken,24L*60L*60L);
        //将token放入响应头
        WebUtil.getResponse().setHeader("access",accessToken);
        WebUtil.getResponse().addHeader("Access-Control-Expose-Headers","access");

        //添加登录日志
        TLoginLog log = new TLoginLog();
        log.setLoginRole(4);
        log.setAccountId(adminInfo.getAdminId());
        log.setAccountName(adminInfo.getAdminName());
        String ipAddr = JwtUtil.getIpAddr(WebUtil.getRequest());
        log.setAddressIp(ipAddr);
        log.setLogInfo("登录成功");
        log.setLogDate(LocalDateTime.now());
        boolean b = tLoginLogService.save(log);
        if (!b) throw new AccountException(LOGIN_ERROR);
        return adminLoginDTO;
    }

    @Override
    public void adminChangePassword(ChangePasswordForm form) throws Exception {
        Integer adminId = JwtUtil.getUserId(1);
        System.out.println(adminId);
        TAdminInfo tAccount = tAdminInfoMapper.selectById(adminId);
        System.out.println(tAccount);
        if(tAccount==null){
            throw  new Exception("信息不存在请确认");
        }
        String salt = tAccount.getAdminName();
        int index=0;//盐的位移数，底层逻辑是通过位移进行加密的
        int count=2;//加密的次数
        //MD5的加密API
        MD5 md5 = new MD5(salt.getBytes(StandardCharsets.UTF_8), index, count);
        if(!tAccount.getAdminPass().equals(md5.digestHex(form.getAccountPass()))){
            throw new AccountException("旧密码输入不正确",400001);
        }
        if(!form.getNewAccountPass().equals(form.getNewAccountPass1())){
            throw new AccountException("两次密码输入不同",400001);
        }
        UpdateWrapper<TAdminInfo> wra = new UpdateWrapper<TAdminInfo>();
        wra.set("admin_pass",md5.digestHex(form.getNewAccountPass()));
        wra.eq("admin_id",tAccount.getAdminId());
        tAdminInfoMapper.update(null,wra);
//        boolean b = updateById(tAccount);
//        System.out.println(b);
//        if (!b) throw new AccountException("修改失败",40000);
//        return true;
    }

    @Override
    public void setAdminAccountState(SetAccountStateForm form) throws Exception {
        Integer adminId = JwtUtil.getUserId(1);
        //未登录
        if (adminId==null) throw new AccountException(USER_NOT_LOGIN);
        if (form.getAdminId() == adminId) throw new AccountException("不能修改自己的账号",40092);
        TAdminInfo admin = getOne(new QueryWrapper<TAdminInfo>().eq("admin_id", form.getAdminId()));
        //不存在
        if (admin==null) throw new AccountException(AccountExceptionCode.NOT_FIND_THIS_ADMIN);
        if (form.getAdminState()!=null) admin.setAdminState(form.getAdminState());
        if (form.getRemark()!=null || !"".equals(form.getRemark())) admin.setRemark(form.getRemark());
        boolean b = updateById(admin);
        if (!b) throw new AccountException(AccountExceptionCode.MODIFICATION_FAILED);
    }

    @Override
    public void setCoachAccountState(SetCoachStateForm form) throws Exception {
        TCoach coach = tCoachMapper.selectById(form.getCoachId());
        if (coach==null) throw new AccountException(NOT_FIND_THIS_COACH);
        if (form.getCoachState()!=null) coach.setCoachState(form.getCoachState());
        if (form.getRemark()!=null || !"".equals(form.getRemark())) coach.setRemark(form.getRemark());
        int i = tCoachMapper.updateById(coach);
        if(i<0){
            throw new AccountException(MODIFICATION_FAILED);
        }
    }

    @Override
    public PageInfo<PageAdminDTO> getAdminByCondition(SearchAdminForm form) throws Exception {
        Page<TAdminInfo> page = new Page<TAdminInfo>(form.getPageNum()==null?1:form.getPageNum(),form.getPageSize()==null?5: form.getPageSize());
        //追加条件
        QueryWrapper<TAdminInfo> wrapper = new QueryWrapper<TAdminInfo>();
        if(ObjectUtil.isAllNotEmpty(form.getCondition())){
            wrapper.like("admin_name",form.getCondition());
            wrapper.or();
            wrapper.eq("admin_phone",form.getCondition());
        }
//        wrapper.orderByAsc("admin_id");
        tAdminInfoMapper.selectPage(page,wrapper);
        List<TAdminInfo> list = page.getRecords();
        ArrayList<PageAdminDTO> data = new ArrayList<>();
        for (TAdminInfo tAdminInfo : list) {
            TAdminRole adminRole = tAdminRoleMapper.selectOne(new QueryWrapper<TAdminRole>().eq("admin_id", tAdminInfo.getAdminId()));
            TRole tRole = tRoleMapper.selectById(adminRole.getRoleId());
            PageAdminDTO dto = BeanUtil.toBean(tAdminInfo, PageAdminDTO.class);
            dto.setRoleName(tRole.getRoleName());
            data.add(dto);
        }
        PageInfo<PageAdminDTO> pageInfo = new PageInfo<>();
        pageInfo.setTotal(Long.valueOf(data.size()));
        pageInfo.setList(data);
        pageInfo.setPages(page.getPages());
        pageInfo.setCurrent(page.getCurrent());
        pageInfo.setSize(page.getSize());
        return pageInfo;
    }

    @Override
    public String uploadImage(UpdateImageForm form) throws Exception {
        TAdminInfo tAdminInfo = tAdminInfoMapper.selectById(form.getAccountId());
        String fileType = FileTypeUtil.getType(form.getImage().getInputStream());
        if(!fileType.equals("jpg")&&!fileType.equals("png")){
            throw new Exception("图片格式不正确");
        }

        String suffix = form.getImage().getOriginalFilename().substring(form.getImage().getOriginalFilename().lastIndexOf("."));
        String name = UUID.randomUUID().toString();
        //String path = aliyunOSSUtil.uploadFile(param.getImage().getInputStream(), name + suffix, "ryusai");
        //新的图片地址
        String url = aliyunOSSUtil.uploadFile(form.getImage().getInputStream(), name + suffix, "ryusai");
        //老的图片地址
        String oldUrl = tAdminInfo.getAdminImage();
        try {
            tAdminInfoMapper.updateById(tAdminInfo);
        }catch (Exception e){
            //没有新增成功
            aliyunOSSUtil.deleteFile("ryusai", FileUtil.getName(url));
        }
        //新增成功了删掉
        aliyunOSSUtil.deleteFile("ryusai",FileUtil.getName(oldUrl));
        tAdminInfo.setAdminImage(url);
        tAdminInfoMapper.updateById(tAdminInfo);
        return url;
    }

    @Override
    public String queryAdminNameById(Integer adminId) throws Exception {
        TAdminInfo info = this.getById(adminId);
        if (info==null){
            throw new AccountException(NOT_FIND_THIS_USER);
        }
        return info.getAdminName();

    }

    @Override
    public PageInfo<UserPointDto> queryAllUserPoint(Integer pageNum, Integer pageSize) throws Exception {
//        Page<TAdminInfo> page = new Page<TAdminInfo>(pageNum==null?1:pageNum,pageSize==null?10: pageSize);
        //先查询课程订单表，算出每一个用户的订单金额

        return null;
    }

}